package com.softer.wxzj.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.softer.wxzj.common.entity.CommonResult;
import com.softer.wxzj.common.entity.Page;
import com.softer.wxzj.common.enums.MessageEnum;
import com.softer.wxzj.common.enums.NumStrEnum;
import com.softer.wxzj.common.enums.NumberEnum;
import com.softer.wxzj.common.enums.ShiroResultEnum;
import com.softer.wxzj.common.error.CourseException;
import com.softer.wxzj.common.flow.enums.FlowStateEnum;
import com.softer.wxzj.common.flow.enums.FlowTypeEnum;
import com.softer.wxzj.common.flow.util.FlowAddAuditUtil;
import com.softer.wxzj.common.flow.util.FlowAuditUtil;
import com.softer.wxzj.common.flow.util.Result;
import com.softer.wxzj.common.logic.ExpReqLogic;
import com.softer.wxzj.common.util.*;
import com.softer.wxzj.entity.*;
import com.softer.wxzj.mapper.*;
import com.softer.wxzj.service.RefReqService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * RefReqServiceImpl class
 *
 * @author zcz
 * @date 2019/1/16
 */
@Service
@Slf4j
public class RefReqServiceImpl implements RefReqService {

    @Autowired
    RefReqMapper refReqMapper;
    @Autowired
    RefReqListMapper refReqListMapper;
    @Autowired
    BaseOwnerInfoMapper baseOwnerInfoMapper;
    @Autowired
    BaseHouseInfoMapper baseHouseInfoMapper;
    @Autowired
    FlowConversionUtil flowConversionUtil;
    @Autowired
    FlowAddAuditUtil flowAddAuditUtil;
    @Autowired
    private OperUtil zoneCodeUtil;
    @Autowired
    private FlowInstanceMapper flowInstanceMapper;
    @Autowired
    private FlowAuditUtil flowUtil;
    @Autowired
    private Result result;
    @Autowired
    private SysCoreParamMapper sysCoreParamMapper;
    @Autowired
    private AccTransactionLogMapper accTransactionLogMapper;
    @Autowired
    private ExpReqLogic expReqLogic;
    @Autowired
    private RefPayInfoMapper refPayInfoMapper;
    @Autowired
    private AccKeepAccountMapper accKeepAccountMapper;
    @Autowired
    private FileServiceImpl fileService;

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public CommonResult refBatchSubmit(List<RefReq> list) {
        int num = NumberEnum.ZERO.getNum();
        BigDecimal payAmount = BigDecimal.ZERO;
        String refType = list.get(0).getRefType();
        for (RefReq refReq : list) {
            BaseHouseInfo info = baseHouseInfoMapper.getInfo(refReq.getAccNo());
            if (null == info) {
                return CommonResult.ResponseResult(num);
            }
            if (null != info && !NumStrEnum.ZERO.getNum().equals(info.getFlowInProgress())) {
                return CommonResult.strResult(NumberEnum.ZERO.getNum(), "部分房屋正在办理：" + flowConversionUtil.getFlowName(info.getFlowInProgress()) + "业务,不能进行申请操作");
            }
            BigDecimal maxPayAmount = getMaxPayAmount(info, refType);
            if (refReq.getPayAmount().compareTo(getMaxPayAmount(info, refType)) == 1) {
                return CommonResult.strResult(NumberEnum.ZERO.getNum(), "部分房屋退款金额不得大于：" + maxPayAmount);
            }
            if (refReq.getPayAmount().compareTo(BigDecimal.ZERO) <= 0) {
                return CommonResult.strResult(NumberEnum.ZERO.getNum(), "部分房屋没有可退款金额！");
            }
            payAmount = payAmount.add(refReq.getPayAmount());
        }
        BaseHouseInfo info = baseHouseInfoMapper.getInfo(list.get(0).getAccNo());
        RefReq req = new RefReq();
        //申请类型 225销户 226部分返还 227全额返还
        String reqNo = getReqNo(refType);
        String flowType = getFlowType(refType);
        //保存申请记录表
        String reqId = UUIDUtil.getUUID();
        req.setId(reqId);
        req.setReason(list.get(0).getReason());
        req.setRefType(refType);
        req.setPayAmount(payAmount);
        req.setBuildId(info.getBuildNo());
        req.setReqType(NumStrEnum.ONE.getNum());
        String orgName = refReqMapper.getOrgNameByHouseId(info.getId());
        req.setReqName(orgName);
        req.setStep(NumStrEnum.ONE.getNum());
        req.setFlowState(NumStrEnum.ZERO.getNum());
        num = insertRefReq(req, reqNo);
        if (num > NumberEnum.ZERO.getNum()) {
            //指定业务id和流程类型
            String initState = flowAddAuditUtil.initFlow(reqId, flowType, null);
            //判断返回值状态   当为2时更新业务表
            list.forEach(l -> {
                l.setRefType(refType);
                l.setId(reqId);
                l.setReqNo(reqNo);
            });
            for (RefReq refReq : list) {
                //保存申请详情表
                insertRefReqList(refReq);
                if (StringUtils.isNotBlank(initState)) {
                    //审批中则更新房屋进行中业务
                    initFlowUpdate(initState, flowType, refReq);
                }
            }
        }
        return CommonResult.ResponseResult(num);
    }

    /**
     * 凭证冻结撤销
     *
     * @param page
     * @param refReq
     * @return
     */
    @Override
    public PageInfo<RefReq> documentFreezingRevocatio(Page page, RefReq refReq) {
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        refReq.setLoginZoneCode(zoneCodeUtil.getZoneCode());
        List<RefReq> list;
        if (StringUtils.isBlank(refReq.getFuzzy())) {
            list = refReqMapper.documentFreezingRevocatio(refReq);
        } else {
            list = refReqMapper.documentFreezingRevocatioFuzzy(refReq.getLoginZoneCode(), refReq.getFuzzy());
        }
        PageInfo<RefReq> pageInfo = new PageInfo<>(list);

        return pageInfo;
    }

    @Override
    public RefReq getRefInfo(String id) {
        return refReqMapper.getRefInfo(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommonResult audit(String id, String opinion, String mark) {
        int i = NumberEnum.ZERO.getNum();
        String auditState = flowAddAuditUtil.audit(id, opinion, mark, null);
        if (null != auditState) {
            RefReq refReq = new RefReq();
            refReq.setId(id);
            refReq.setFlowState(auditState);
            //不在审核中则更新业务表
            if (!FlowStateEnum.IN_AUDIT.getState().equals(auditState)) {
                refReq.setRecDate(DateUtils.getNow());
                if (FlowStateEnum.VETO.getState().equals(auditState)) {
                    List<RefReqList> refReqLists = refReqListMapper.getListByReqId(id);
                    //设置记账表状态为撤销
                    accTransactionLogMapper.updateStateByBusiNo(NumStrEnum.ZERO.getNum(), id);
                    BaseHouseInfo houseInfo = new BaseHouseInfo();
                    refReqLists.forEach(r -> {
                        BaseHouseInfo baseHouseInfo = baseHouseInfoMapper.getInfo(r.getHouseId());
                        if (FlowTypeEnum.CLOSE_ACCOUNT.getType().equals(baseHouseInfo.getFlowInProgress()) || FlowTypeEnum.REF_REQ.getType().equals(baseHouseInfo.getFlowInProgress())) {
                            houseInfo.setFlowInProgress(NumStrEnum.ZERO.getNum());
                        }
                        BigDecimal accountFrozen = null == baseHouseInfo || null == baseHouseInfo.getAccountFrozen() ? BigDecimal.ZERO : baseHouseInfo.getAccountFrozen();
                        houseInfo.setAccountFrozen(accountFrozen.subtract(r.getPayAmount()));
                        houseInfo.setId(r.getHouseId());
                        houseInfo.setDueState(getDueState(r.getHouseId()));
                        houseInfo.setState(NumStrEnum.ONE.getNum());
                        baseHouseInfoMapper.refVetoHouse(houseInfo);
                    });
                }
            }
            i = refReqMapper.update(refReq);
        }
        return CommonResult.ResponseResult(i);
    }

    /**
     * 生成缴存状态
     *
     * @param houseId
     * @return
     */
    private String getDueState(String houseId) {
        String dueState = NumStrEnum.ZERO.getNum();
        BigDecimal depTotalPayAmount = accTransactionLogMapper.getLogDepTotalPayAmount(houseId);
        BigDecimal refTotalPayAmount = accTransactionLogMapper.getLogRefTotalPayAmount(houseId);
        BigDecimal money = depTotalPayAmount.subtract(refTotalPayAmount);
        BaseHouseInfo info = baseHouseInfoMapper.getInfo(houseId);
        if (money.compareTo(info.getFirstDue()) == 1) {
            dueState = NumStrEnum.TWO.getNum();
        } else if (money.compareTo(info.getFirstDue()) == -1) {
            dueState = NumStrEnum.THREE.getNum();
        } else if (money.compareTo(info.getFirstDue()) == 0) {
            dueState = NumStrEnum.ONE.getNum();
        }
        return dueState;
    }

    /**
     * 有效日期列表
     *
     * @param id
     * @return
     */
    @Override
    public RefReq selectVaildDateById(String id) {
        RefReq refReq = refReqMapper.selectVaildDateById(id);
        return refReq;
    }

    @Override
    public PageInfo<RefReq> selectAllReqRefState(Page page, RefReq refReq) {
        //赋值区域,重要
        refReq.setLoginZoneCode(zoneCodeUtil.getZoneCode());
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        List<RefReq> list = refReqMapper.selectAllReqRefState(refReq);
        PageInfo<RefReq> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    public PageInfo<RefReq> getCancelRevokeList(Page page, RefReq refReq) {
        refReq.setLoginZoneCode(zoneCodeUtil.getZoneCode());
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        List<RefReq> list = refReqMapper.getCancelRevokeList(refReq);
        PageInfo<RefReq> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommonResult refCancel(String id) {
        int num = NumberEnum.ZERO.getNum();
        //查询是否记账
        RefReq refInfo = refReqMapper.getInfo(id);
        List<RefPayInfo> refPayInfos = refPayInfoMapper.selectListByReqId(id);
        for (RefPayInfo refPayInfo : refPayInfos) {
            if (refPayInfo.getAccNoState().equals(NumStrEnum.FOUR.getNum())) {
                throw new CourseException(ShiroResultEnum.FAIL.getCode(), "该业务的部分数据已经记账，无法撤销");
            }
        }
        if (null == refInfo || NumStrEnum.FOUR.getNum().equals(refInfo.getStep()) || !NumStrEnum.TWO.getNum().equals(refInfo.getFlowState())) {
            return CommonResult.strResult(num, "请检查数据状态！");
        }
        //批量改房屋进行中业务为0
        //refReqMapper.batchUpdateHouseProgressByReqId(id);
        List<RefReqList> listByReqId = refReqListMapper.getListByReqId(id);
        refRevokeHouse(listByReqId);
        //申请表状态为撤销
        RefReq refReq = new RefReq();
        refReq.setId(id);
        refReq.setState(NumStrEnum.ZERO.getNum());
        for (RefPayInfo refPayInfo : refPayInfos) {
            if (null != refPayInfo) {
                int n = refPayInfoMapper.updatByReqId(id);
                if (n == NumberEnum.ZERO.getNum()) {
                    throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
                }
                if (StringUtils.isNotBlank(refPayInfo.getPayNo())) {
                    n = accKeepAccountMapper.updateState(NumStrEnum.ZERO.getNum(), refPayInfo.getPayNo());
                    if (n == NumberEnum.ZERO.getNum()) {
                        throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
                    }
                }
            }
        }
        num = refReqMapper.update(refReq);
        return CommonResult.ResponseResult(num);
    }

    /**
     * 撤销房屋退款信息
     *
     * @param listByReqId
     * @return
     */
    private int refRevokeHouse(List<RefReqList> listByReqId) {
        int num = NumberEnum.ZERO.getNum();
        for (RefReqList refReqList : listByReqId) {
            //查询房间冻结金额
            BaseHouseInfo baseHouseInfo = baseHouseInfoMapper.getInfo(refReqList.getHouseId());
            BigDecimal accountFrozen = null == baseHouseInfo.getAccountFrozen() ? BigDecimal.ZERO : baseHouseInfo.getAccountFrozen();
            //恢复当前业务状态为0  冻结金额 = 冻结金额 - 退款金额
            BaseHouseInfo houseInfo = new BaseHouseInfo();
            houseInfo.setId(refReqList.getHouseId());
            if (FlowTypeEnum.CLOSE_ACCOUNT.getType().equals(baseHouseInfo.getFlowInProgress()) || FlowTypeEnum.REF_REQ.getType().equals(baseHouseInfo.getFlowInProgress())) {
                houseInfo.setFlowInProgress(NumStrEnum.ZERO.getNum());
            }
            BigDecimal decimal = accountFrozen.subtract(refReqList.getPayAmount());
            houseInfo.setAccountFrozen(decimal);
            houseInfo.setState(NumStrEnum.ONE.getNum());
            houseInfo.setDueState(getDueState(refReqList.getHouseId()));
            num = baseHouseInfoMapper.refRevokeHouse(houseInfo);
        }
        return num;
    }


    @Override
    public PageInfo<RefReq> getRefList(Page page, RefReq refReq) {
        refReq.setLoginZoneCode(zoneCodeUtil.getZoneCode());
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        List<RefReq> list = refReqMapper.getRefList(refReq);
        PageInfo<RefReq> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    public PageInfo<RefReq> getBatchRefundList(Page page, RefReq refReq) {
        refReq.setLoginZoneCode(zoneCodeUtil.getZoneCode());
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        List<RefReq> list = refReqMapper.getBatchRefundList(refReq);
        PageInfo<RefReq> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    public PageInfo<RefReq> getAuditList(Page page, RefReq refReq) {
        //查询业务
        Map<String, String> map = flowUtil.getBussIdAndZoneCodeByOperNo(FlowTypeEnum.REF_REQ.getType() + "," + FlowTypeEnum.CLOSE_ACCOUNT.getType());
        List<RefReq> list = new ArrayList<>();
        if (null != map) {
            result.select(map, refReq);
            PageHelper.startPage(page.getPageNum(), page.getPageSize());
            list = refReqMapper.getAuditList(refReq);
            list.forEach(ref -> {
                        ref.setAddress(ref.getAddress() + "(" + ref.getHouseCount() + ")");
                        switch (ref.getRefTypeCode()) {
                            case "225":
                                ref.setFlowType("close_account");
                                break;
                            case "226":
                                ref.setFlowType("ref_req");
                                break;
                            case "227":
                                ref.setFlowType("ref_req");
                                break;
                        }
                    }

            );
        }
        PageInfo<RefReq> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    public PageInfo<RefPayInfo> getRefPayInfoByReqId(@RequestParam("id") String id, Page page, String fuzzy) {
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        List<RefPayInfo> list = refReqMapper.getRefPayInfoByReqId(id, fuzzy);
        PageInfo<RefPayInfo> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public CommonResult save(RefReq refReq) {
        int num;
        //查询是否在途中业务
        BaseHouseInfo info = baseHouseInfoMapper.getInfo(refReq.getAccNo());
        if (null != info && !NumStrEnum.ZERO.getNum().equals(info.getFlowInProgress())) {
            return CommonResult.strResult(NumberEnum.ZERO.getNum(), "房屋正在办理：" + flowConversionUtil.getFlowName(info.getFlowInProgress()) + "业务,不能进行申请操作");
        }
        if (refReq.getPayAmount().compareTo(getMaxPayAmount(info, refReq.getRefType())) == 1) {
            return CommonResult.strResult(NumberEnum.ZERO.getNum(), "退款金额不得大于：" + getPayAmount(info, refReq.getRefType()));
        }
        if (refReq.getPayAmount().compareTo(BigDecimal.ZERO) <= 0) {
            return CommonResult.strResult(NumberEnum.ZERO.getNum(), "没有可退款金额！");
        }
        String isExpState = expReqLogic.getIsExpInProgress(info.getId());
        if (NumStrEnum.ONE.getNum().equals(isExpState)) {
            return CommonResult.strResult(NumberEnum.ZERO.getNum(), "使用在途,无法退款！");
        }
        num = flowInstanceMapper.selectChangeHouseAndOwner(info.getId(), "base_house_info_update");
        if (num > 0) {
            return CommonResult.strResult(NumberEnum.ZERO.getNum(), "房屋变更,无法退款！");
        } else {
            num = flowInstanceMapper.selectChangeHouseAndOwner(info.getId(), "base_owner_info_update");
            if (num > 0) {
                return CommonResult.strResult(NumberEnum.ZERO.getNum(), "业主变更,无法退款！");
            }
        }
        //申请类型 225销户 226部分返还 227全额返还
        String reqNo = getReqNo(refReq.getRefType());
        //保存申请记录表
        String reqId = UUIDUtil.getUUID();
        refReq.setId(reqId);
        String ownerName = refReqMapper.getOwnerNameByHouseId(info.getId());
        refReq.setReqName(ownerName);
        refReq.setBuildId(info.getBuildNo());
        refReq.setReqType(NumStrEnum.ZERO.getNum());
        refReq.setStep(NumStrEnum.ZERO.getNum());
        refReq.setFlowState(NumStrEnum.FOUR.getNum());
        num = insertRefReq(refReq, reqNo);
        if (num == NumberEnum.ZERO.getNum()) {
            throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
        }
        //保存申请详情表
        int count = insertRefReqList(refReq);
        if (count == NumberEnum.ZERO.getNum()) {
            throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
        }
        //区分流程类型
        String flowType = getFlowType(refReq.getRefType());
        BaseHouseInfo houseInfo = new BaseHouseInfo();
        houseInfo.setId(refReq.getAccNo());
        houseInfo.setFlowInProgress(flowType);
        num = baseHouseInfoMapper.update(houseInfo);
        if (num == NumberEnum.ZERO.getNum()) {
            throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
        }
        return CommonResult.ResponseResult(num);
    }

    /**
     * 提交审核
     *
     * @param id 退款ID
     * @return 提交结果
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public CommonResult refSingleSubmit(String id, String arcType, String accNo) {
        //校验图档必传项
        CommonResult result = fileService.checkFile(id, arcType);
        if (ShiroResultEnum.FAIL.getCode() == result.getData()) {
            return result;
        }
        RefReq refReq = refReqMapper.getInfo(id);
        refReq.setAccNo(accNo);
        refReq.setFlowState(NumStrEnum.ZERO.getNum());
        refReq.setStep(NumStrEnum.ONE.getNum());
        refReq.setModifier(ShiroUserUtil.getUser().getOperName());
        int update = refReqMapper.update(refReq);
        if (update == 0) {
            return CommonResult.ResponseResult(update);
        }
        //区分流程类型
        String flowType = getFlowType(refReq.getRefType());
        //指定业务id和流程类型
        int i = initFlow(refReq, flowType);
        if (i == NumberEnum.ZERO.getNum()) {
            throw new CourseException(ShiroResultEnum.FAIL.getCode(), MessageEnum.FAIL.getMsg());
        }
        return CommonResult.ResponseResult(i);
    }


    /**
     * 生成reqNo
     *
     * @param refType
     * @return
     */
    private String getReqNo(String refType) {
        String reqNo = null;
        switch (refType) {
            case "225":
                reqNo = DepositUtil.getNo("6");
                break;
            case "226":
                reqNo = DepositUtil.getNo("2");
                break;
            case "227":
                reqNo = DepositUtil.getNo("3");
                break;
        }
        return reqNo;
    }

    /**
     * 生成reqNo
     *
     * @param refType
     * @return
     */
    private String getFlowType(String refType) {
        String flowType = null;
        switch (refType) {
            case "225":
                flowType = FlowTypeEnum.CLOSE_ACCOUNT.getType();
                break;
            case "226":
                flowType = FlowTypeEnum.REF_REQ.getType();
                break;
            case "227":
                flowType = FlowTypeEnum.REF_REQ.getType();
                break;
        }
        return flowType;
    }

    /**
     * 保存申请表
     *
     * @param refReq
     * @param reqNo
     * @return
     */
    private int insertRefReq(RefReq refReq, String reqNo) {
        refReq.setReqNo(reqNo);
        refReq.setCreater(ShiroUserUtil.getUserName());
        refReq.setReqOper(ShiroUserUtil.getUserName());
        return refReqMapper.insert(refReq);
    }

    /**
     * 保存申请详情表
     *
     * @param refReq
     * @return
     */
    private int insertRefReqList(RefReq refReq) {
        BaseHouseInfo info = baseHouseInfoMapper.getInfo(refReq.getAccNo());
        BaseOwnerInfo baseOwnerInfo = baseOwnerInfoMapper.getInfoByAccNo(refReq.getAccNo());
        RefReqList reqList = new RefReqList();
        reqList.setOwnerId(baseOwnerInfo.getId());
        reqList.setId(UUIDUtil.getUUID());
        reqList.setHouseId(refReq.getAccNo());
        reqList.setReqId(refReq.getId());
        //退款本金
        BigDecimal payFundAmount = BigDecimal.ZERO;
        BigDecimal payAccrCal = BigDecimal.ZERO;
        //申请类型 225销户 226部分返还 227全额返还
        switch (refReq.getRefType()) {
            case "225":
                payFundAmount = info.getFundBal();
                //销户、全额退款计算截止当前利息     部分退款不参与计算
                payAccrCal = getPayAccrCal(refReq.getRefType(), refReq.getAccNo());
                refReq.setPayAccrAmount(payAccrCal);
                //保存记账表
                saveAccTransactionLog(refReq.getAccNo(), refReq.getReqNo(), payAccrCal);
                break;
            case "226":
                if (info.getFundBal().compareTo(refReq.getPayAmount()) < 0) {
                    payAccrCal = refReq.getPayAmount().subtract(info.getFundBal());
                    payFundAmount = info.getFundBal();
                } else {
                    payFundAmount = refReq.getPayAmount();
                }
                break;
            case "227":
                payFundAmount = info.getFundBal();
                //销户、全额退款计算截止当前利息     部分退款不参与计算
                payAccrCal = getPayAccrCal(refReq.getRefType(), refReq.getAccNo());
                refReq.setPayAccrAmount(payAccrCal);
                //保存记账表
                saveAccTransactionLog(refReq.getAccNo(), refReq.getReqNo(), payAccrCal);
                break;
        }
        reqList.setPayFundAmount(payFundAmount);
        reqList.setPayAccrAmount(info.getAccrBal());
        reqList.setPayAccrCal(payAccrCal);
        reqList.setPayAmount(refReq.getPayAmount());
        reqList.setReqOper(ShiroUserUtil.getUserName());
        reqList.setCreater(ShiroUserUtil.getUserName());
        return refReqListMapper.insert(reqList);
    }

    /**
     * 初始化审批流
     *
     * @param refReq
     * @param flowType
     * @return
     */
    public int initFlow(RefReq refReq, String flowType) {
        int num = NumberEnum.ZERO.getNum();
        //指定业务id和流程类型
        String initState = flowAddAuditUtil.initFlow(refReq.getId(), flowType, null);
        //判断返回值状态   当为2时更新业务表
        if (StringUtils.isNotBlank(initState)) {
            //审批中则更新房屋进行中业务
            num = initFlowUpdate(initState, flowType, refReq);
        }
        return num;
    }

    private int initFlowUpdate(String initState, String flowType, RefReq refReq) {
        int num;
        BaseHouseInfo houseInfo = new BaseHouseInfo();
        houseInfo.setId(refReq.getAccNo());
        String flowInProgress = flowType;
        //houseInfo状态  3待销户  4待退房
        //申请类型 225销户 226部分返还 227全额返还
        switch (refReq.getRefType()) {
            case "225":
                houseInfo.setState(NumStrEnum.THREE.getNum());
                break;
            case "227":
                houseInfo.setState(NumStrEnum.FOUR.getNum());
                break;
        }
        houseInfo.setFlowInProgress(flowInProgress);
        houseInfo.setAccountFrozen(refReq.getPayAmount());
        //查询房间冻结金额
        BaseHouseInfo baseHouseInfo = baseHouseInfoMapper.getInfo(refReq.getAccNo());
        BigDecimal accountFrozen = null == baseHouseInfo.getAccountFrozen() ? BigDecimal.ZERO : baseHouseInfo.getAccountFrozen();
        //冻结金额 = 冻结金额 + 退款金额
        BigDecimal decimal = accountFrozen.add(refReq.getPayAmount());
        houseInfo.setAccountFrozen(decimal);
        num = baseHouseInfoMapper.update(houseInfo);
        if (num > 0 && NumStrEnum.TWO.getNum().equals(initState)) {
            RefReq req = new RefReq();
            req.setId(refReq.getId());
            req.setRecDate(DateUtils.getNow());
            req.setFlowState(initState);
            req.setModifier(ShiroUserUtil.getUser().getOperName());
            num = refReqMapper.update(req);
        }
        return num;
    }


    @Override
    public CommonResult insert(RefReq refReq) {
        return null;
    }

    @Override
    public CommonResult update(RefReq refReq) {
        return null;
    }

    @Override
    public CommonResult delete(String id) {
        return null;
    }

    @Override
    public PageInfo<RefReq> getList(Page page, RefReq refReq) {
        return null;
    }

    @Override
    public RefReq getInfo(String id) {
        return null;
    }

    /**
     * 部分退款检查是否可以退款提示
     *
     * @param ownerId
     * @param refType
     * @return
     */
    @Override
    public CommonResult drawback(String ownerId, String refType) {
        return checkRefReq(ownerId, refType);
    }

    /**
     * 全额退款检查是否可以退款提示
     *
     * @param ownerId
     * @param refType
     * @return
     */
    @Override
    public CommonResult selectpayAmount(String ownerId, String refType) {
        return checkRefReq(ownerId, refType);
    }

    private CommonResult checkRefReq(String ownerId, String refType) {
        int r = 0;
        String type = "退款";
        BaseHouseInfo baseHouseInfo = baseHouseInfoMapper.getInfoByOwnerId(ownerId);
        if (null != baseHouseInfo && !NumStrEnum.ZERO.getNum().equals(baseHouseInfo.getFlowInProgress())) {
            switch (baseHouseInfo.getFlowInProgress()) {
                case "ref_req":
                    type = getType(refType, type);
                    return CommonResult.ResponseResult(r, "该房间退款在途，无法" + type + "!");
                case "close_account":
                    type = getType(refType, type);
                    return CommonResult.ResponseResult(r, "该房间销户在途，无法" + type + "!");
                case "base_owner_info_update":
                    type = getType(refType, type);
                    return CommonResult.ResponseResult(r, "该房间业主变更在途，无法" + type + "!");
                case "base_house_info_update":
                    type = getType(refType, type);
                    return CommonResult.ResponseResult(r, "该房间房屋变更在途，无法" + type + "!");
                case "trans_req":
                    type = getType(refType, type);
                    return CommonResult.ResponseResult(r, "该房间房屋过户在途，无法" + type + "!");
                case "deposit":
                    type = getType(refType, type);
                    return CommonResult.ResponseResult(r, "该房间房屋缴存在途，无法" + type + "!");
                case "deposit_continuation":
                    type = getType(refType, type);
                    return CommonResult.ResponseResult(r, "该房间房屋续交在途，无法" + type + "!");
                default:
                    type = getType(refType, type);
                    return CommonResult.ResponseResult(r, "该房屋有在途使用业务，无法" + type + "!");
            }
        }
        //是否有使用在途业务
        if (TWO_HUNDRED_AND_TWENTY_FIVE.equals(refType) || TWO_HUNDRED_AND_TWENTY_SEVEN.equals(refType)) {
            //使用在途:不影响部分退款,不可全额退款、销户
            if (NumStrEnum.ZERO.getNum().equals(baseHouseInfo.getFlowInProgress())) {
                String isExpState = expReqLogic.getIsExpInProgress(baseHouseInfo.getId());
                if (NumStrEnum.ONE.getNum().equals(isExpState)) {
                    return CommonResult.ResponseResult(r, "该房间使用在途，无法" + type + "!");
                }
            }
        }
        //交存在途:不可全额退款、部分退款、销户
        if (NumStrEnum.ZERO.getNum().equals(baseHouseInfo.getFlowInProgress())) {
            BaseOwnerInfo baseOwnerInfo = baseOwnerInfoMapper.getInfoByAccNo(baseHouseInfo.getId());
            int count = baseHouseInfoMapper.getCountDepReqListByHouseId(baseHouseInfo.getId(), baseOwnerInfo.getId());
            if (count > 0) {
                return CommonResult.ResponseResult(r, "该房间缴存在途，无法" + type + "!");
            }
        }
        //退款金额
        BigDecimal pay = getMaxPayAmount(baseHouseInfo, refType);
        if (pay.compareTo(BigDecimal.ZERO) == 1) {
            return CommonResult.ResponseResult(1);
        } else {
            return CommonResult.ResponseResult(r, "该房屋账户无可退金额");
        }
    }

    private static final String TWO_HUNDRED_AND_TWENTY_FIVE = "225";
    private static final String TWO_HUNDRED_AND_TWENTY_SEVEN = "227";

    private String getType(String refType, String type) {
        if (TWO_HUNDRED_AND_TWENTY_FIVE.equals(refType)) {
            type = "销户";
        }
        return type;
    }

    /**
     * 可退款的最大金额
     *
     * @param baseHouseInfo
     * @param refType
     * @return
     */
    protected BigDecimal getMaxPayAmount(BaseHouseInfo baseHouseInfo, String refType) {
        BigDecimal maxPayAmount = getPayAmount(baseHouseInfo, refType);
        if (TWO_HUNDRED_AND_TWENTY_FIVE.equals(refType) || TWO_HUNDRED_AND_TWENTY_SEVEN.equals(refType)) {
            BigDecimal payAccrCal = getPayAccrCal(refType, baseHouseInfo.getId());
            maxPayAmount = maxPayAmount.add(payAccrCal);
        }
        return maxPayAmount;
    }

    @Override
    public BaseHouseInfo getRefInfoByOwnerId(String ownerId, String refType) {
        BaseOwnerInfo b = baseOwnerInfoMapper.getInfo(ownerId);
        BaseHouseInfo baseHouseInfo = refReqMapper.getRefInfoByOwnerId(ownerId, b.getAccNo(), refType);
        //截止当前利息
        BigDecimal accr = getPayAccrCal(refType, baseHouseInfo.getId());
        //退款金额
        BigDecimal payAmount = getMaxPayAmount(baseHouseInfo, refType);
        BigDecimal money = baseHouseInfo.getAccrBal().add(accr);
        baseHouseInfo.setAccrBal(money);
        baseHouseInfo.setPayAmount(payAmount);
        baseHouseInfo.setSellerInterest(money);
        return baseHouseInfo;
    }

    @Override
    public PageInfo<RefReq> getPartRefundList(Page page, RefReq refReq) {
        refReq.setLoginZoneCode(zoneCodeUtil.getZoneCode());
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        List<RefReq> list = refReqMapper.getPartRefundList(refReq);
        for (RefReq r : list) {
            r.setFlowState(r.getFlowStateCode());
            //全额退款/销户 并且记账后查询交易表
            if (null == r.getOwnerName() && null == r.getCertNo() && null == r.getOwnerNo()) {
                RefReqList ownerInfo = refReqListMapper.getOwnerInfoByPayNo(r.getPayNo());
                if (null != ownerInfo) {
                    r.setOwnerName(ownerInfo.getOwnerName());
                    r.setCertNo(ownerInfo.getCertNo());
                    r.setOwnerNo(ownerInfo.getOwnerNo());
                }
            }
        }
        PageInfo<RefReq> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    /**
     * 计算销户、退款的截止当前利息
     *
     * @param refType
     * @param houseId
     * @return
     */
    protected BigDecimal getPayAccrCal(String refType, String houseId) {
        //截止当前利息总金额
        BigDecimal payAccrCal = BigDecimal.ZERO;
        String isCalculate = NumStrEnum.ZERO.getNum();
        String value = NumStrEnum.ZERO.getNum();
        switch (refType) {
            case "225":
                isCalculate = sysCoreParamMapper.getParamValueByCode("19");
                value = sysCoreParamMapper.getParamValueByCode("20");
                break;
            case "227":
                isCalculate = sysCoreParamMapper.getParamValueByCode("17");
                value = sysCoreParamMapper.getParamValueByCode("18");
                break;
        }
        if (NumStrEnum.ONE.getNum().equals(isCalculate)) {
            Date dateNow = DateFormatUtil.getNowDate();
            BigDecimal yearRate = new BigDecimal(value);
            BigDecimal rate = yearRate.divide(new BigDecimal(36000), 15, RoundingMode.HALF_UP);
            //查询log表所有记账记录
            List<AccTransactionLog> logs = accTransactionLogMapper.getListByHouseId(houseId);
            List<AccTransactionLog> logList;
            //查询log表最大结息记账记录
            Date maxCalculateTallyDate = accTransactionLogMapper.getMaxCalculateTallyDateByHouseId(houseId);
            //存在
            if (null != maxCalculateTallyDate) {
                //过滤需要计息的记账节点  以结息日期为起点  分段计息  结息 <= 记账 && 记账 <= 当前
                logList = logs.stream().filter(log -> (!DateFormatUtil.getDateFormat(log.getTallyDate(), "yyyy-MM-dd").before(maxCalculateTallyDate) && !dateNow.before(DateFormatUtil.getDateFormat(log.getTallyDate(), "yyyy-MM-dd")))).collect(Collectors.toList());
                payAccrCal = getNotePayAccrCal(logList, dateNow, rate);
            } else {
                payAccrCal = getNotePayAccrCal(logs, dateNow, rate);
            }
        }
        //上截取两位
        payAccrCal = payAccrCal.setScale(2, RoundingMode.FLOOR);
        log.info(refType + "计算截止当前利息为：" + payAccrCal);
        return payAccrCal;
    }

    /**
     * 节点结息总利息
     *
     * @param logList
     * @param dateNow
     * @param rate
     * @return
     */
    private BigDecimal getNotePayAccrCal(List<AccTransactionLog> logList, Date dateNow, BigDecimal rate) {
        BigDecimal payAccrCal = BigDecimal.ZERO;
        BigDecimal nodePayAccrCal;
        for (int i = 0; i < logList.size(); i++) {
            int days = NumberEnum.ZERO.getNum();
            //不为最后一次记账时  天数 = 后一次记账 - 前一次记账日期
            if (i < logList.size() - 1) {
                days = DateFormatUtil.getDiscrepantDays(DateFormatUtil.getDateFormat(logList.get(i).getTallyDate(), "yyyy-MM-dd"), DateFormatUtil.getDateFormat(logList.get(i + 1).getTallyDate(), "yyyy-MM-dd"));
            }
            //最后一次记账   天数 = 当前日期 - 前一次记账日期
            if (i == logList.size() - 1) {
                days = DateFormatUtil.getDiscrepantDays(DateFormatUtil.getDateFormat(logList.get(i).getTallyDate(), "yyyy-MM-dd"), dateNow);
            }
            nodePayAccrCal = logList.get(i).getFundBal().multiply(rate).multiply(BigDecimal.valueOf((long) days));
            payAccrCal = payAccrCal.add(nodePayAccrCal);
        }
        return payAccrCal;
    }

    /**
     * 全额退款销户保存记录表
     *
     * @param houseId
     * @param busiNo
     * @param payAmount
     * @return
     */
    private int saveAccTransactionLog(String houseId, String busiNo, BigDecimal payAmount) {
        //查询业主
        BaseOwnerInfo ownerInfo = baseOwnerInfoMapper.getInfoByAccNo(houseId);
        AccTransactionLog log = new AccTransactionLog();
        log.setId(UUIDUtil.getUUID());
        log.setHouseId(houseId);
        log.setBusiNo(busiNo);
        log.setBusiType("313");
        log.setAccountType("325");
        log.setIoFlag("In");
        log.setPayAmount(payAmount);
        log.setFundBal(BigDecimal.ZERO);
        log.setAccountFrozen(BigDecimal.ZERO);
        log.setAccrBal(BigDecimal.ZERO);
        log.setOwnerId(ownerInfo.getId());
        log.setState(NumStrEnum.TWO.getNum());
        log.setTallyDate(DateUtils.getDateNow());
        return accTransactionLogMapper.insert(log);
    }

    @Override
    public CommonResult refRevoke(String id) {
        //查询状态0待审核的才可撤销
        RefReq info = refReqMapper.getInfo(id);
        int num = NumberEnum.ZERO.getNum();
        if (null != info) {
            if (!NumStrEnum.ZERO.getNum().equals(info.getFlowState())) {
                return CommonResult.strResult(num, "已被审核，无法撤销！");
            }
            RefReq req = new RefReq();
            req.setId(id);
            req.setState(NumStrEnum.ZERO.getNum());
            //改状态为撤销
            num = refReqMapper.update(req);
            //删除审批实例
            flowInstanceMapper.deleteByBussinessId(id);
            List<RefReqList> listByReqId = refReqListMapper.getListByReqId(id);
            //撤销修改房屋对应信息
            refRevokeHouse(listByReqId);
            //批量变更房屋表当前业务为0
            //如果log表有截止当前利息则修改为撤销
            accTransactionLogMapper.updateStateByBusiNo(NumStrEnum.ZERO.getNum(), id);
        }
        return CommonResult.ResponseResult(num);
    }

    /**
     * 凭证打印列表
     *
     * @param page
     * @param houseAndOwner
     * @return
     */
    @Override
    public PageInfo<HouseAndOwner> selectReqRefState(Page page, HouseAndOwner houseAndOwner) {
        List<HouseAndOwner> list;
        houseAndOwner.setLoginZoneCode(zoneCodeUtil.getZoneCode());
        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        if (StringUtils.isBlank(houseAndOwner.getFuzzy())) {
            list = refReqMapper.selectReqRefState(houseAndOwner);
        } else {
            list = refReqMapper.selectReqRefStateFuzzy(houseAndOwner.getLoginZoneCode(), houseAndOwner.getFuzzy());
        }
        PageInfo<HouseAndOwner> pageInfo = new PageInfo<>(list);
        return pageInfo;
    }

    /**
     * 退款金额
     *
     * @param baseHouseInfo
     * @param refType
     * @return
     */
    private BigDecimal getPayAmount(BaseHouseInfo baseHouseInfo, String refType) {
        BigDecimal payAmount;
        BigDecimal fundBal = null == baseHouseInfo.getFundBal() ? BigDecimal.ZERO : baseHouseInfo.getFundBal();
        BigDecimal accrBal = null == baseHouseInfo.getAccrBal() ? BigDecimal.ZERO : baseHouseInfo.getAccrBal();
        switch (refType) {
            //申请类型 225销户 226部分返还 227全额返还
            case "226":
                payAmount = getPartRefPayAmount(baseHouseInfo.getId());
                break;
            default:
                payAmount = fundBal.add(accrBal);
                break;
        }
        return payAmount;
    }

    /**
     * 部分退款金额计算
     *
     * @param houseId
     * @return
     */
    private BigDecimal getPartRefPayAmount(String houseId) {
        BaseHouseInfo baseHouseInfo = baseHouseInfoMapper.getInfo(houseId);
        BigDecimal refPayAmount = BigDecimal.ZERO;
        //交存总记账
        BigDecimal depTotalPayAmount = accTransactionLogMapper.getLogDepTotalPayAmount(baseHouseInfo.getId());
        //总退款记账
        BigDecimal refTotalPayAmount = accTransactionLogMapper.getLogRefTotalPayAmount(baseHouseInfo.getId());
        //交存剩余金额
        BigDecimal refSurplusTotalAmount = depTotalPayAmount.subtract(refTotalPayAmount);
        //交存剩余金额 > 初交应交金额
        if (refSurplusTotalAmount.compareTo(baseHouseInfo.getFirstDue()) == 1) {
            //余额 = 账户余额 - 冻结+利息
            if (null == baseHouseInfo.getFundBal()) {
                baseHouseInfo.setFundBal(BigDecimal.ZERO);
            }
            if (null == baseHouseInfo.getAccountFrozen()) {
                baseHouseInfo.setAccountFrozen(BigDecimal.ZERO);
            }
            if (null == baseHouseInfo.getAccrBal()) {
                baseHouseInfo.setAccrBal(BigDecimal.ZERO);
            }
            BigDecimal balance = baseHouseInfo.getFundBal().subtract(baseHouseInfo.getAccountFrozen()).add(baseHouseInfo.getAccrBal());
            //预应退 = 交存剩余金额 - 初交应交
            BigDecimal preAmount = refSurplusTotalAmount.subtract(baseHouseInfo.getFirstDue());
            //预应退 >= 剩余  剩余            预应退 < 剩余  预应退
            refPayAmount = preAmount.compareTo(balance) == -1 ? preAmount : balance;
        }
        return refPayAmount;
    }

}
